package com.example.upload.serviceImpl.user;

import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.example.upload.annotation.RunTimeMonotor;
import com.example.upload.constant.DeleteStatus;
import com.example.upload.constant.SystemDefault;
import com.example.upload.constant.UserStatus;
import com.example.upload.dto.user.LoginDto;
import com.example.upload.dto.user.RegisterDto;
import com.example.upload.entity.user.User;
import com.example.upload.exception.BusinessRuntimeException;
import com.example.upload.mapper.user.UserMapper;
import com.example.upload.service.user.UserService;
import com.example.upload.tool.IDGenerator;
import com.example.upload.tool.MD5Utils;
import org.apache.commons.lang3.ObjectUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @author lsx
 * @description: TODO
 * @date 2024年06月07日 16:03
 * @Version: 1.0
 */
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private RedissonClient redissonClient;

    @Override
    public void register(RegisterDto registerDto) {
        try {
            registerDto.setPassword(MD5Utils.getSaltMD5(registerDto.getPassword()));
            User user = new User();
            BeanUtils.copyProperties(registerDto,user);
            user.setStatus(UserStatus.NORMAL.getCode());
            user.setCreateBy(SystemDefault.SYSTEM);
            user.setCreateTime(System.currentTimeMillis());
            user.setDeleted(DeleteStatus.UNDELETE.getCode());
            user.setPersonId(IDGenerator.generateID());
            User existUser = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getTell, registerDto.getTell()).eq(User::getDeleted, DeleteStatus.UNDELETE.getCode()));
            if(ObjectUtils.isNotEmpty(existUser)){
                throw new BusinessRuntimeException("该手机号已被注册，请勿重复注册！");
            }
            user.setBucketName(UUID.randomUUID().toString().replaceAll("-", "").substring(1,4) +"files");
            userMapper.insert(user);
        } catch (BeansException e) {
            throw new BusinessRuntimeException("注册失败，请重新注册！");
        }
    }

    @Override
    @RunTimeMonotor
    public void login(LoginDto loginDto) {
        User user = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getTell, loginDto.getTell()).eq(User::getDeleted, DeleteStatus.UNDELETE.getCode()));
        if (ObjectUtils.isEmpty(user)){
            throw new BusinessRuntimeException("该手机号未注册，请先注册！");
        }
        if (!MD5Utils.getSaltverifyMD5(loginDto.getPassword(),user.getPassword())){
            throw new BusinessRuntimeException("密码错误，请重新输入！");
        }
        if (user.getStatus() != UserStatus.NORMAL.getCode()){
            throw new BusinessRuntimeException("该账号已被禁用，请联系管理员！");
        }
        StpUtil.login(user.getPersonId());
    }

    @Override
    public void lockExecution(String tell, Runnable runnable) {
        String key = String.format("fileUpload:user:%s",tell);
        RLock lock = null;
        try {
            lock = redissonClient.getLock(key);
            if(org.springframework.util.ObjectUtils.isEmpty(lock)){
                throw new BusinessRuntimeException("注册失败，未获取到锁！");
            }
            boolean haveLock = lock.tryLock(60, 60, TimeUnit.SECONDS);
            if (haveLock) {
                runnable.run();
            }else{
                throw new BusinessRuntimeException("注册失败，加锁失败！");
            }
        } catch (InterruptedException e) {
            BusinessRuntimeException bre = new BusinessRuntimeException("注册失败，请重新注册!");
            bre.initCause(e);
            throw bre;
        }
        finally {
            if (!org.springframework.util.ObjectUtils.isEmpty(lock) && lock.isLocked()) {
                lock.unlock();
            }
        }
    }
}
